/*
 *      css_parser.cpp
 *      
 *      Copyright 2009 Aaron Lehrian <jsmaster@tampabay.rr.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */


#include "css_parser.h"
#include "css_location.h"
#include <string.h>
#include <string>

css_parser::css_parser()
{
	currenttype = 0;
	currentnum = 0;
	idlength = 0;
	classlength = 0;
	taglength = 0;
}


css_parser::~css_parser()
{
	
}

void css_parser::parse(css_document *d,char *f)
{
	file = f;
	doc = d;
	currentnum = 0;
	
	stripcomments();
	
	for(pos = 0;pos<(int)strlen(file);){
		
		openblock();

		while(ret = addattribute()){	   //repeat until code block ends
			if(ret < 1){
				break;
			}
		}
		closeblock();
		
	
	}
}


void css_parser::stripcomments(){
	
	tmp = file;
	while((tmp = strstr(tmp,"/*"))){
		tmp2 = strstr(tmp,"*/");
		commentlength = (tmp2-tmp)+strlen("*/");
		memset(tmp,' ',commentlength);
	}
	tmp = file;
	while((tmp = strstr(tmp,"//"))){
		tmp2 = strchr(tmp,'\n');
		commentlength = (tmp2-tmp)+1;
		memset(tmp,' ',commentlength);
	}
	
}


void css_parser::openblock(){
	while(file[pos] != '{'){
		while((int)file[pos] < 33 && file[pos])	pos++;			//clear white space
		temp = new css_property;
		currenttype = 0;
		first = true;	
		while((int)file[pos] > 32 && (int)file[pos] < 123 && file[pos] != ',' && file[pos] != '{'){
			switch(file[pos]){
			case '.':
				idlength = 0;
				currenttype |= CLASS;
				pos++;
				classnamep = file + pos;
				first = false;
				break;
			case '#':
				idlength = 0;
				currenttype |= ID;
				pos++;
				idnamep = file + pos;
				first = false;
				break;
			default:
				if(first){
					taglength = 0;
					currenttype |= TAG;
					tagnamep = file + pos;
					first = false;
				}
				if(!((currenttype & ID) || (currenttype & CLASS))){
					taglength++;
				}
				else if((currenttype & ID)){
					idlength++;
				}
				else if((currenttype & CLASS)){
					classlength++;
				}
				pos++;
				break;
			}
		}
		temp->location->settype(currenttype);
	
	
		if(idlength && (currenttype & ID)){
			idname = new char [idlength+1];
			strncpy(idname,idnamep,idlength);
			idname[idlength] = '\0';
			temp->location->setvalue(ID,idname);
			delete [] idname;
			idlength = 0;
		}
		if(classlength && (currenttype & CLASS)){
			classname = new char [classlength+1];
			strncpy(classname,classnamep,classlength);
			classname[classlength] = '\0';
			temp->location->setvalue(CLASS,classname);
			delete [] classname;
			classlength = 0;
		}
		if(taglength && (currenttype & TAG)){
			tagname = new char [taglength+1];
			strncpy(tagname,tagnamep,taglength);
			tagname[taglength] = '\0';
			temp->location->setvalue(TAG,tagname);
			delete [] tagname;
			taglength = 0;
		}
		doc->doc_properties.push_back(temp);
		if(file[pos] != '{') pos++;
		while((int)file[pos] < 33 && file[pos])	pos++;			//clear white space
	}
}

void css_parser::closeblock(){
	currentnum = doc->doc_properties.size();
	while((int)file[pos] < 33 && file[pos]) pos++;
}

int css_parser::addattribute(){
	while((int)file[pos] < 33 && file[pos]) pos++;   //Whitespace
	if(file[pos] == '}'){
		pos++;
		return 0;
	}
	if(file[pos] == '{'){		//Oening of code block
		pos++;
		while((int)file[pos] < 33 && file[pos]) pos++;	//Whitespace
	}
	idp = file + pos;
	idlength = 0;
	while(file[pos] != ':' && pos<strlen(file)){
		pos++;
		idlength++;
	}
	pos++;
	id = new char [idlength+1];
	strncpy(id,idp,idlength);
	while((int)file[pos] < 33 && file[pos]) pos++;	//Whitespace
	vlength = 0;
	valuep = file + pos;
	while(file[pos] != ';' && file[pos] != '\n' && file[pos] != '}' && file[pos]){     //Until current attribute ends (let setvalue() take care of multiple attributes on one line)
		vlength++;
		pos++;
	}
	value = new char [vlength+1];
	strncpy(value,valuep,vlength);
	value[vlength] = '\0';
	for(int pushnum = currentnum;pushnum < doc->doc_properties.size();pushnum++){
		current = new css_attribute;
		current->setvalue(current->ctoid(id),value);
		doc->doc_properties[pushnum]->attrib.push_back(current);
	}
	delete [] value;
	delete [] id;
	if(file[pos] == '}'){
		pos++;
		return 0;
	}
	else if(pos == strlen(file)){
		return -1;						//error
	}
	else{
		pos++;
		return 1;
	}
}

